package it.univpm.diiga.semanticsearch.gestione;
import it.univpm.diiga.semanticsearch.configurazione.Configuration;
import it.univpm.diiga.semanticsearch.servizi.Link;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;







public class GestioneRepository {

	DocumentBuilderFactory dbf;
	DocumentBuilder db;
	Document document=null;
	
	private String localLink, localFormat;
	
	
	public GestioneRepository() {
	
		try {
			Configuration.findRepoConfiguration();
		
			String file=Configuration.getPublicRepoLink().get(0).getFile();
			localLink="webapps"+file;
			localFormat="xml";
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
		
			e.printStackTrace();
					
	/*		try{
			FileWriter fstream = new FileWriter("out.txt");
	        BufferedWriter out = new BufferedWriter(fstream);
	    out.write(e.toString());
	    //Close the output stream
	    out.close();		
			}
			catch(Exception a){}
	*/
			
		}
		
	
    	
	}
	
	
	
	public ArrayList<Link> readRepository(String link) throws Exception {
		
		

		this.parseRepository(link);
		
		
		//popola la lista dei servizi presenti nel repository
						
		String wsdl="";
		String bpel="";
		String swsal="";
		String servLink="";
		String servName="";
		String servRepo=localLink;

		String servDescr="";
	
		ArrayList<Link> services=new ArrayList<Link>();
		
		
			 	Element rootEle = document.getDocumentElement();
				
			 if (rootEle!=null){
				 
				 
			 
			 	NodeList list_serv = rootEle.getElementsByTagName("service");
				for(int i = 0 ; i < list_serv.getLength();i++) {
	
					Element service = (Element)list_serv.item(i);
					
					                 
					
					NodeList list_ele = service.getElementsByTagName("name");
	                if(list_ele != null && list_ele.getLength() > 0) {
	                    Element ele = (Element)list_ele.item(0);
	                   
	                    
	                    if (ele.hasChildNodes()){ // if node exist
	                     servName = ele.getFirstChild().getNodeValue().toLowerCase();
	                    
	                     
	                     
	     				
	                    }else{servName = "undefined";} // invalid xml service entry(blank name)
	                }else{servName = "undefined";}
	                

	                
	                
	                	list_ele = service.getElementsByTagName("wsdl");
	                    if(list_ele != null && list_ele.getLength() > 0) {
	                        Element ele = (Element)list_ele.item(0);
	                        if (ele.hasChildNodes()){ // if node exist
	                         wsdl = ele.getFirstChild().getNodeValue();
	                        // System.out.println("   Wsdl: "+wsdl);
	                        }else{wsdl =null;} // invalid xml service wsdl entry(blank wsdl)
	                    }else{wsdl =null;}
	                    
	                    
	                    
	                	list_ele = service.getElementsByTagName("bpel");
	                    if(list_ele != null && list_ele.getLength() > 0) {
	                        Element ele = (Element)list_ele.item(0);
	                        if (ele.hasChildNodes()){ // if node exist
	                         bpel = ele.getFirstChild().getNodeValue();
	                       //  System.out.println("   Bpel: "+bpel);
	                        }else{bpel =null;} // invalid xml service bpel entry(blank bpel)
	                    }else{bpel =null;}
	                    
	                	list_ele = service.getElementsByTagName("swsal");
	                    if(list_ele != null && list_ele.getLength() > 0) {
	                        Element ele = (Element)list_ele.item(0);
	                        if (ele.hasChildNodes()){ // if node exist
	                         swsal = ele.getFirstChild().getNodeValue();
	                       //  System.out.println("   Swsal: "+swsal);
	                        }else{swsal =null;} // invalid xml service swsal entry(blank swsal)
	                    }else{swsal =null;}
	                    
	                	list_ele = service.getElementsByTagName("servLink");
	                    if(list_ele != null && list_ele.getLength() > 0) {
	                        Element ele = (Element)list_ele.item(0);
	                        if (ele.hasChildNodes()){ // if node exist
	                         servLink = ele.getFirstChild().getNodeValue();
	                       //  System.out.println("   Link servizio: "+servLink);
	                        }else{servLink =null;} // invalid xml service link entry(blank link)
	                    }else{servLink =null;}
	                    
	                    //COSTRUISCE L'OGGETTO LINK CON I CAMPI
	                    //SOPRA ACQUISITI
	                    Link serv=new Link(servName,servLink,wsdl,bpel,swsal,servRepo);
	                    
	                    
	                    
	                  //ACQUISICE I RESTANTI CAMPI: DESCRIPTION E META, E LI INSERISCE NELL'OGGETTO LINK
		                list_ele = service.getElementsByTagName("description");
		                if(list_ele != null && list_ele.getLength() > 0) {
		                    Element ele = (Element)list_ele.item(0);
		                   
		                    
		                    if (ele.hasChildNodes()){ // if node exist
		                     servDescr = ele.getFirstChild().getNodeValue().toLowerCase();
		                    
		                     
		     				
		                    }else{servDescr = null;}
		                }else{servDescr = null;}
		                
		                serv.setServDescr(servDescr); //aggiunge la descrizione all'oggetto link
		                
		            
		            list_ele = service.getElementsByTagName("meta");
					if(list_ele != null && list_ele.getLength() > 0) {
			           for(int j1 = 0 ; j1 < list_ele.getLength();j1++) { 
			                    Element ele = (Element)list_ele.item(j1);
			                   
			                    
			                    if (ele.hasChildNodes()){ // if node exist
			                    	//aggiunge ciascun meta-tag trovato all'oggetto link
			                    	serv.addServMeta(ele.getFirstChild().getNodeValue().toLowerCase());
			                     
			                    }//else{servMeta.add("undefined");}

						}
					}

	                    
	                    
	                   services.add(serv); //aggiunge l'oggetto link all'elenco dei servizi
	                }
	                
	    
		
		return services;
		
			 }
			 else{
			 //services.add(new Link(null,null,null,null,null,null));
			 return services;
			 }
		
	}
	
	
	
	public void addRepository(Link serv, int position) throws Exception{
	
		if(position<0){ //if no service has been selected in the list
						//append the new service to the bottom

			this.parseRepository(localLink);
			
			//first we create the xml model with the service added
			
					//gets the root element<repository>
				Element rootEle = document.getDocumentElement();
			
	          		//Creates <service> xml element from the link object and append it to root
				Element xmlservice = getXMLservice(serv);
				rootEle.appendChild(xmlservice);
				
				
			//at last we save the new Xml to local repository file
				this.printToFile(localLink);
				
			
			
		}else{//inserts the service in the middle of the dom tree, rebuilding the tree itself
			
			ArrayList<Link> services = this.readRepository(localLink);
			
			try {
				document=dbf.newDocumentBuilder().newDocument();
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
			}
			
			document.appendChild(document.createElement("repository"));
			Element rootEle =document.getDocumentElement();
			
			for(int i=0;i<services.size();i++){
			
				Element xmlserv;
				
				if (i==position){
					xmlserv = getXMLservice(serv);
					rootEle.appendChild(xmlserv);
				}
				
				xmlserv = getXMLservice(services.get(i));
				rootEle.appendChild(xmlserv);
				
			}
			
			//at last we save the new Xml to local repository file
			this.printToFile(localLink);
			
		}
		
		
		
	}
	
	
	public void modRepository(Link serv, int position) throws Exception{
		
		//modify the service in the middle of the dom tree, rebuilding the tree itself
		
		ArrayList<Link> services = this.readRepository(localLink);
		
		try {
			document=dbf.newDocumentBuilder().newDocument();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		
		document.appendChild(document.createElement("repository"));
		Element rootEle =document.getDocumentElement();
		
		for(int i=0;i<services.size();i++){
		
			Element xmlserv;
			
			if (i==position){
				xmlserv = getXMLservice(serv);
				rootEle.appendChild(xmlserv);
			}else{			
			xmlserv = getXMLservice(services.get(i));
			rootEle.appendChild(xmlserv);
			}
		}
		
		//at last we save the new Xml to local repository file
		this.printToFile(localLink);
	
		
	}

	
	/**
	 * Method which gets a XML element <service> from a Link object
	 */
    private Element getXMLservice(Link serv){

		Element xmlservice = document.createElement("service");
		//create name element and name text node and attach it to service
		Element name = document.createElement("name");
		Text txtname;
		if(serv.getServName()!=null){
			 txtname = document.createTextNode(serv.getServName());
		}else{
			 txtname = document.createTextNode("undefined");
		}
		name.appendChild(txtname);
		
		
		//create servlink element and servlink text node and attach it to service
		Element servlink = document.createElement("servLink");
		Text txtservlink;
		if(serv.getServLink()!=null){
		    txtservlink = document.createTextNode(serv.getServLink());
		}else{
        	txtservlink = document.createTextNode("not specified");
        }
		servlink.appendChild(txtservlink);
        

		//create wsdl element and wsdl link text node and attach it to service
		Element wsdl = document.createElement("wsdl");
		Text txtwsdl;
		if(serv.getWsdlLink()!=null){
		     txtwsdl = document.createTextNode(serv.getWsdlLink());
		}else{
			 txtwsdl = document.createTextNode("not specified");
		}
		wsdl.appendChild(txtwsdl);
		
        //create bpel element and bpel text node and attach it to service
		Element bpel = document.createElement("bpel");
		Text txtbpel;
		if(serv.getBpellLink()!=null){
		    txtbpel = document.createTextNode(serv.getBpellLink());
		}else{
			txtbpel = document.createTextNode("not specified");
		}
		bpel.appendChild(txtbpel);
        
        //create swsal element and swsal text node and attach it to service
		Element swsal  = document.createElement("swsal");
		Text txtswsal;
		if(serv.getSwsalLink()!=null){
            txtswsal = document.createTextNode(serv.getSwsalLink());
		}else{
			txtswsal = document.createTextNode("not specified");
		}
		swsal.appendChild(txtswsal);
		
		
		//create description element and description text node and attach it to service
		Element description  = document.createElement("description");
		Text txtdescr;
		if(serv.getServDescr()!=null){
            txtdescr = document.createTextNode(serv.getServDescr());
		}else{
			txtdescr = document.createTextNode("No description");
		}
		description.appendChild(txtdescr);
        
        
                xmlservice.appendChild(name);
                xmlservice.appendChild(servlink);
                xmlservice.appendChild(wsdl);
                xmlservice.appendChild(bpel);
                xmlservice.appendChild(swsal);
                xmlservice.appendChild(description);
                
                
                //test
      //create meta-tag elements and meta-tag text nodes and attach these to service
        		
                if(serv.getServMeta().size()>0){
                
                	for(int i=0;i<serv.getServMeta().size();i++){
                		                
                		Element metatag  = document.createElement("meta");
                		Text txtmeta;
                		if(serv.getServMeta().get(i)!=null){
                			txtmeta = document.createTextNode(serv.getServMeta().get(i));
                		}else{
                			txtmeta = document.createTextNode("undef");
                		}
                		
                		metatag.appendChild(txtmeta);
                		
                		xmlservice.appendChild(metatag);
                	} 
                }

                
                
		return xmlservice;

	}
	
	
	public void delRepository(ArrayList<Integer> selection) throws Exception{
	
						
		//il codice seguente rimuove dall'albero DOM la selezione
			
			this.parseRepository(localLink);
			
				Element rootEle = document.getDocumentElement();
            			//get a nodelist of <service> elements
				NodeList list_serv = rootEle.getElementsByTagName("service");
    
				//JOptionPane.showMessageDialog(null, (nl!=null) + " "+ nl.getLength() + " "  + selection.get(i));

		if(list_serv!=null && list_serv.getLength()>0) {
				
			for(int i=0;i<selection.size();i++){
				
				if((selection.get(i)-i)<=list_serv.getLength()){
							//	removes the service
						rootEle.removeChild(list_serv.item(selection.get(i)-i));
                    }
				}
		}
		
		
		this.printToFile(localLink); //L'invocazione del metodo printToFile, 
									 //permette di salvare su file le modifiche effettuate
		
			
			
		
		
	}
	
	
	
	
	public void import_rep(String externalLink) throws Exception{
		
		ArrayList<Link> imported_serv = new ArrayList<Link>();
		imported_serv = this.readRepository(externalLink);
		
		for(int i=0;i<imported_serv.size();i++){
			this.addRepository(imported_serv.get(i), -1);
		}
		
		
	}
	
	
	public String getLink(){
	
		return localLink;
	}
	
	
	
	public String getFormat_repository(){
	
		
		return localFormat;
		
	}
	
	

	
	

	private void parseRepository(String link) throws Exception{
		
		//try {
			dbf = DocumentBuilderFactory.newInstance();	
			db = dbf.newDocumentBuilder();
			document= db.parse(link);
		
		/*} catch (ParserConfigurationException e) {
			
				e.printStackTrace();
				try {document=dbf.newDocumentBuilder().newDocument();} 
				catch (ParserConfigurationException ex) {}
				}
		 catch (SAXException e) {
			
//			  e.printStackTrace();
			 	 try {document=dbf.newDocumentBuilder().newDocument();} 
			 	 catch (ParserConfigurationException ex) {}
        
			 if(link.equalsIgnoreCase(localLink)){ 
				JOptionPane.showMessageDialog(null, "Error reading local Repository!\nCheck for "
						+"errors in the xml file("+ link +")\n(Eg. blank file, missing of tags closures, <repository> tag\nmust"+
						" be closed at the end of file with </repository>, etc.)", "Reading Error",2);
			 }
			 else{
				 JOptionPane.showMessageDialog(null, "Error reading Repository!\nCheck for "
							+"errors in the xml file("+ link +")\n(Eg. blank or wrong file, missing of tags closures, <repository> tag\nmust"+
							" be closed at the end of file with </repository>, etc.)", "Import Error",2);
			 }
		 		}
		 catch (IOException e) {
			 System.out.println("Errore gestione");
			 	e.printStackTrace();					
			 	try {document=dbf.newDocumentBuilder().newDocument();} 
                catch (ParserConfigurationException ex) {}
		 	}*/
		 
		

	}

	
	
    /**
	 * This method uses Xerces specific classes
	 * prints the XML document to file.
         */

	
	
	private boolean printToFile(String filename){
            
            boolean status;
		
			try { 
		
				// Prepare the DOM document for writing (SOURCE) 
				Source source = new DOMSource(document); 
				
				// Prepare the output file  (DESTINATION)
				File file = new File(filename); 
				Result result = new StreamResult(file);
				
				
				// Write the DOM document to the file  
				Transformer xformer = TransformerFactory.newInstance().newTransformer(); 
				xformer.transform(source, result); 
                
				status=true;
				
			} catch (TransformerConfigurationException e) { status=false; } 
			catch (TransformerException e) { status=false;} 

			
			return status;
		
 }
    


	
	/*
	private void changeLink(){
		
		
	}
	*/


	/*
	public void changeFormat_repository(){
		
		
	}
	*/
	
	
	
	
}
